#include <iostream>
#include <fstream>
#include "card.h"
#include "deck.h"

using namespace std;


void reshuffleDeck ( deck &drawDeck, deck &discardDeck );


int main () {
	// file locations
	string deckFileLocation = "./empty.gdf";

	// decks
	deck drawDeck;	// stores the cards that are waiting to be drawn
	deck dieRollDeck;	// stores the cards that carry out the actions of a die roll card
	deck discardDeck;	// stores the cards that have been discarded
	deck handDeck;	// stores the cards that are in the player's hand
	deck tableauDeck;	// stores the cards that are sitting in the player's tableau
	
	// deck restrictions
	int allowedHandSize = 5;	// the default hand size is 5 unless a card modifies it
	int allowedTableauSize = 4;	// the default tableau size is 4 unless a card modifies it
	
	// cards
	card currentCard;	// the card that is currently being played
	
	// state identifiers
	char keepPlaying = 'y';	// the exercise will continue until this is false
	char playToTableau;	// determines whether a drawn card is played or discarded
	int tableauIndexToReplace;	// which card from the tableau should be replaced when adding to a full tableau
	
	// initialize things
	cout << "Building the initial deck ... ";
	drawDeck.buildDeck ( deckFileLocation );	// build the initial draw deck
	cout << "Done, " << drawDeck.cardsInDeck () << " cards loaded" << endl << "Shuffling ... ";
	drawDeck.shuffle ();	// shuffle the initial draw deck
	cout << "Done" << endl;
	
	// main program loop
	while ( keepPlaying == 'y' ) {
		// show the current deck counts and tableau
		cout << "Cards Remaining in the Draw Deck: " << drawDeck.cardsInDeck () << endl;
		cout << "Cards in the Discard Deck: " << discardDeck.cardsInDeck () << endl;
		cout << "Current Tableau: ";
		if ( tableauDeck.cardsInDeck () > 0 ) {
			cout << tableauDeck.cardsInDeck () << endl << endl;
			for ( int cardIter = 0; cardIter < tableauDeck.cardsInDeck (); cardIter++ ) {
				cout << "Card " << cardIter + 1 << endl;
				cout << "Name: " << tableauDeck.thisCardName (cardIter) << endl;
				cout << "Color/Category: " << tableauDeck.thisCardColor (cardIter) << " / " << tableauDeck.thisCardCategory (cardIter) << endl;
				cout << "Description: " << tableauDeck.thisCardDescription (cardIter) << endl;
			}
			cout << endl;
		}
		else {
			cout << "Empty" << endl;
		}

		// draw a card and show it
		if ( drawDeck.cardsInDeck () == 0 ) {
			#ifdef DEBUG_ALL
			cout << "DEBUG: Draw deck is empty, going to reshuffle." << endl;
			#endif

			reshuffleDeck ( drawDeck, discardDeck );

			#ifdef DEBUG_ALL
			cout << "DEBUG: Cards reshuffled." << endl;
			#endif
		}

		if ( drawDeck.cardsInDeck () > 0 ) {	// if there are cards in the draw deck
			currentCard = drawDeck.drawCard ();

			#ifdef DEBUG_ALL
			cout << "DEBUG: Card drawn." << endl;
			#endif

			cout << "You Drew This Card: " << endl;
			cout << "Name: " << currentCard.name << endl;
			cout << "Color/Category: " << currentCard.color << " / " << currentCard.category << endl;
			cout << "Description: " << currentCard.description << endl << endl;
			
			// decide what to do with the drawn card
			playToTableau = 'x';	// set to an out-of-bounds value to ensure the loop runs at least once
			while ( playToTableau != 'y' && playToTableau != 'n' ) {
				cout << "Play the current card? (y/n): ";
				cin >> playToTableau;
				
				if ( playToTableau != 'y' && playToTableau != 'n' ) {
					cout << "Invalid input." << endl;
				}
			}
		
			// play or discard the drawn card
			if ( playToTableau == 'y' ) {
				if ( tableauDeck.cardsInDeck () < allowedTableauSize ) {	// check for empty tableau slots
					tableauDeck.addCard ( currentCard );	// add the current card to the tableau
	
					#ifdef DEBUG_ALL
					cout << "DEBUG: Card added to the tableau." << endl;
					#endif
				}
				else {
					// decide which card to replace
					tableauIndexToReplace = -1;	// set to an out-of-bounds value to ensure the loop runs at least once
					while ( tableauIndexToReplace < 1 || tableauIndexToReplace > tableauDeck.cardsInDeck () ) {
						cout << "Which card should be replaced (use card number): ";
						cin >> tableauIndexToReplace;					
					}
					tableauIndexToReplace--;	// decrement index to accommodate index 0
					
					// replace the chosen card with the current card
					discardDeck.addCard ( tableauDeck.takeCard ( tableauIndexToReplace ) );	// move the desired card from the tableau to the discard deck
					tableauDeck.addCard ( currentCard );	// add the current card to the tableau
	
					#ifdef DEBUG_ALL
					cout << "DEBUG: Card replaced in the tableau." << endl;
					#endif
				}
			}
			else {
				discardDeck.addCard ( currentCard );
				cout << "Card discarded." << endl;
			}
		}
		else {	// there are no cards in the draw deck
			cout << "No card was drawn because there are no cards available in the deck. This should not happen when the deck has been properly loaded." << endl;
		}
			
		// decide whether to keep going
		keepPlaying = 'x';	// set to an out-of-bounds value to ensure the loop runs at least once
		while ( keepPlaying != 'y' && keepPlaying != 'n' ) {
			cout << "Keep playing? (y/n): ";
			cin >> keepPlaying;
			
			if ( keepPlaying != 'y' && keepPlaying != 'n' ) {
				cout << "Invalid input." << endl;
			}
		}
		cout << endl;	// insert a line break before the next turn starts
	}
	
	return ( 0 );
}


void reshuffleDeck ( deck &drawDeck, deck &discardDeck ) {
	/*	Moves all of the cards from the discard deck to the draw deck and then shuffles the draw deck.
		Preconditions:	The draw deck is empty.
		Postconditions:	The original contents of the discard deck are in the draw deck and the draw deck is shuffled.	*/
	
	while ( !discardDeck.isEmpty () ) {	// while there are still cards in the discard deck
		drawDeck.addCard ( discardDeck.drawCard () );	// draw a card from the discard deck and put it on the draw deck
	}

	#ifdef DEBUG_ALL
	cout << "DEBUG: All cards moved from discard to draw deck." << endl;
	#endif
	
	drawDeck.shuffle ();	// shuffle the now-filled draw deck

	#ifdef DEBUG_ALL
	cout << "DEBUG: Draw deck shuffled." << endl;
	#endif
}
